package com.pshcp.patient.api;

import cn.hutool.core.date.DateUtil;
import com.external.common.WebServiceException;
import com.external.service.WsRequestService;
import com.external.ws.soap.entity.res.Remain;
import com.framework.base.PageList;
import com.framework.base.ResultBuilder;
import com.framework.base.ResultDTO;
import com.framework.common.config.CustomConf;
import com.framework.exception.BizException;
import com.framework.logaop.Log;
import com.framework.logaop.LogSourceEnum;
import com.framework.logaop.LogTypeEnum;
import com.framework.thread.ReqComHold;
import com.framework.tool.CommonTool;
import com.pshcp.common.enums.CommonStatusEnum;
import com.pshcp.common.enums.DoctorHomeTypeEnum;
import com.pshcp.common.enums.DoctorListTypeEnum;
import com.pshcp.common.enums.RegTypeEnum;
import com.pshcp.common.tool.PhotoTools;
import com.pshcp.domain.dto.DoctorAnnouncementDTO;
import com.pshcp.domain.dto.DoctorDTO;
import com.pshcp.domain.dto.DoctorDiagnosisEvaluationDTO;
import com.pshcp.domain.dto.DoctorIntroDTO;
import com.pshcp.domain.dto.DoctorOrderCountDTO;
import com.pshcp.domain.dto.PatientFavorDTO;
import com.pshcp.domain.model.Dept;
import com.pshcp.domain.model.DeptDoctorDescRel;
import com.pshcp.domain.model.Doctor;
import com.pshcp.domain.model.DoctorAnnouncement;
import com.pshcp.domain.model.DoctorDiagnosisEvaluation;
import com.pshcp.domain.model.DoctorDiagnosisSettings;
import com.pshcp.domain.model.DoctorSchedule;
import com.pshcp.domain.model.Patient;
import com.pshcp.domain.vo.DoctorAnnouncementVO;
import com.pshcp.patient.domain.doctor.ao.DoctorAnnouncementAO;
import com.pshcp.patient.domain.doctor.ao.DoctorAnnouncementListAO;
import com.pshcp.patient.domain.doctor.ao.DoctorDescAO;
import com.pshcp.patient.domain.doctor.ao.DoctorEvaAddAO;
import com.pshcp.patient.domain.doctor.ao.DoctorEvaListAO;
import com.pshcp.patient.domain.doctor.ao.DoctorIntroAO;
import com.pshcp.patient.domain.doctor.ao.DoctorOnlineStatusAO;
import com.pshcp.patient.domain.doctor.ao.DoctorScheduleAO;
import com.pshcp.patient.domain.doctor.ao.DoctorScheduleDayAO;
import com.pshcp.patient.domain.doctor.ao.RegHomeAO;
import com.pshcp.patient.domain.doctor.vo.DoctorEvaListVO;
import com.pshcp.patient.domain.doctor.vo.DoctorIntroVO;
import com.pshcp.patient.domain.doctor.vo.DoctorScheduleVO;
import com.pshcp.patient.domain.doctor.vo.HosAreaVO;
import com.pshcp.patient.domain.doctor.vo.RegHomeVO;
import com.pshcp.patient.tool.DoctorTools;
import com.pshcp.service.DeptDoctorDescRelService;
import com.pshcp.service.DeptService;
import com.pshcp.service.DoctorAnnouncementService;
import com.pshcp.service.DoctorDiagnosisEvaluationService;
import com.pshcp.service.DoctorDiagnosisSettingsService;
import com.pshcp.service.DoctorScheduleService;
import com.pshcp.service.DoctorService;
import com.pshcp.service.OrderRegService;
import com.pshcp.service.PatientFavorService;
import com.pshcp.service.PatientOnlineOrderService;
import com.pshcp.service.PatientService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Api(tags = {"患者端-医生"})
@Slf4j
@RestController
@RequestMapping("/api/patient/doctor")
public class DoctorInfoAPI {

    @Autowired
    private WsRequestService wsRequestService;

    @Autowired
    private DoctorScheduleService scheduleService;

    @Autowired
    private DoctorService doctorService;

    @Autowired
    private PatientService patientService;

    @Autowired
    private PatientFavorService patientFavorService;

    @Autowired
    private OrderRegService orderRegService;

    @Autowired
    private PatientOnlineOrderService onlineOrderService;

    @Autowired
    private DeptService deptService;

    @Autowired
    private DoctorAnnouncementService announcementService;

    @Autowired
    private DoctorDiagnosisEvaluationService evaluationService;

    @Autowired
    private CustomConf customConf;

    @Autowired
    private DoctorDiagnosisSettingsService doctorDiagnosisSettingsService;

    @Autowired
    private DeptDoctorDescRelService deptDoctorDescRelService;

    @Value("${custom.desc.app-name}")
    private String appName;

    @Value("${custom.patient.reg-refresh-time:15:00:00}")
    private String regRefreshTime;

    @Value("${custom.patient.reg-limit-day:7}")
    private Integer regLimitDay;

    @Value("#{'${custom.desc.areas}'.split(',')}")
    private List<String> areas;

    @ApiOperation("院区选择")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.SELECT, desc = "院区选择")
    @PostMapping("/areaChoose")
    public ResultDTO<List<HosAreaVO>> areaChoose(){
        List<HosAreaVO> voList = new ArrayList<>();
        areas.forEach(item -> {
            String[] areas = item.split("#");
            HosAreaVO vo = new HosAreaVO();
            vo.setName(areas[0]);
            vo.setAddress(areas[1]);
            vo.setId(Integer.parseInt(areas[2]));
            vo.setImg(areas[3]);
            voList.add(vo);
        });
        return ResultBuilder.success(voList);
    }

    @ApiOperation("医生排班时间")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.SELECT, desc = "医生排班时间")
    @PostMapping("/scheduleDay")
    public ResultDTO<List<String>> scheduleDay(@RequestBody DoctorScheduleDayAO scheduleDayAO){
        List<String> days = new ArrayList<>();
        if(RegTypeEnum.TODAY.getCode().equals(scheduleDayAO.getRegType())){
            days.add(DateUtil.today());
            return ResultBuilder.success(days);
        }
        //下午3点 自动放号
        int limitDay = regLimitDay;
        if(DateUtil.current() >
                DateUtil.parseDateTime(DateUtil.today() + " " + regRefreshTime).getTime()){
            limitDay ++;
        }
        String limitDateStr = DateUtil.offsetDay(new Date(), limitDay).toDateStr();
        for(int i = 1; i <= limitDay; i++){
            String temp = DateUtil.offsetDay(DateUtil.parseDate(scheduleDayAO.getSchDate()), i).toDateStr();
            if(temp.compareTo(limitDateStr) > 0){
                break;
            }
            days.add(temp);
        }
        return ResultBuilder.success(days);
    }


    @ApiOperation("医生排班")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.SELECT, desc = "医生排班")
    @PostMapping("/schedule")
    public ResultDTO<List<DoctorScheduleVO>> schedule(@Valid @RequestBody DoctorScheduleAO scheduleAO) throws WebServiceException {

        List<DoctorSchedule> schedulings = scheduleService.list(DoctorTools.buildScheduleAO2DTO(scheduleAO));
        List<DoctorScheduleVO> voList = DoctorTools.buildScheduleVOS(schedulings);
        if(CollectionUtils.isEmpty(voList)){
            return ResultBuilder.success(voList);
        }
        // 调用HIS接口 排班状态确认
        List<Remain> remains = wsRequestService.remainQuery(DoctorTools.buildWsRemainQueryDTO(schedulings, scheduleAO));
        DoctorTools.buildScheduleRemainInfo(voList, remains);
        //当日挂号(get 在线挂号量、医生擅长)
        if(DateUtil.today().equals(scheduleAO.getSchDate())){
            buildDoctorInfo(voList);
        }
        return ResultBuilder.success(voList);
    }

    private void buildDoctorInfo(List<DoctorScheduleVO> voList){
        //擅长
        List<String> doctorHisIds = voList.stream().map(DoctorScheduleVO::getHisDoctorId).collect(Collectors.toList());
        List<Doctor> doctors = doctorService.findByHisDoctorIds(doctorHisIds);
        Map<String, String> hisIdAndGoodAtMap = doctors.stream().filter(d -> !ObjectUtils.isEmpty(d.getGoodAt())).collect(Collectors.toMap(d-> d.getHisDoctorId(), d-> d.getGoodAt(), (v1,v2)->v1));
        Map<Long, String> idAndHisIdMap = doctors.stream().collect(Collectors.toMap(d->d.getId(), d-> d.getHisDoctorId()));
        //挂号量
        List<Long> doctorIds = doctors.stream().map(Doctor::getId).collect(Collectors.toList());
        List<DoctorOrderCountDTO> orderCountDTOS = orderRegService.countByDoctorIds(doctorIds);
        Map<String, Integer> hisIdAndCountMap = new HashMap<>();
        orderCountDTOS.forEach(oc -> {
            String hisId = idAndHisIdMap.get(oc.getDoctorId());
            hisIdAndCountMap.put(hisId, oc.getNum());
        });

        voList.forEach(vo -> {
            vo.setGoodAt(hisIdAndGoodAtMap.get(vo.getHisDoctorId()));
            vo.setRegCount(hisIdAndCountMap.get(vo.getHisDoctorId()));
        });
    }

    @ApiOperation("挂号/医生主页")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.SELECT, desc = "挂号/医生主页")
    @PostMapping("/regHome")
    public ResultDTO<RegHomeVO> regHome(@RequestBody RegHomeAO regHomeAO) throws BizException {
        //base info
        Doctor doctor = doctorService.findByHisDoctorId(regHomeAO.getHisDoctorId());
        CommonTool.checkObj(doctor, "10120001");
        RegHomeVO regHomeVO = DoctorTools.buildRegHomeVO(doctor, customConf.getFileUrl());

        List<Dept> depts = deptService.getDeptListByDoctorId(doctor.getId());
        DoctorTools.buildRegHomeVODept(regHomeVO, depts);
        //关注量
        int favorCount = patientFavorService.doctorFavorNum(doctor.getId());
        regHomeVO.setFavorNum(favorCount);
        //挂号量
        int regCount = orderRegService.doctorRegCount(doctor.getId());
        regHomeVO.setRegNum(regCount);
        //是否关注
        PatientFavorDTO favorDTO = new PatientFavorDTO();
        favorDTO.setStatus(CommonStatusEnum.INIT.getCode());
        favorDTO.setDoctorId(doctor.getId());
        favorDTO.setPatientUserId(ReqComHold.getReqCom().getUserId());
        int isFavor = patientFavorService.listCount(favorDTO);
        regHomeVO.setFavor(isFavor > 0);
        return ResultBuilder.success(regHomeVO);
    }

    @ApiOperation("在线咨询")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.SELECT, desc = "在线咨询")
    @PostMapping("/introduce")
    public ResultDTO<PageList<DoctorIntroVO>> introduce(@RequestBody DoctorIntroAO doctorIntroAO) {
        PageList<Doctor> doctorPageList = doctorService.list(DoctorTools.buildDoctorDTO(doctorIntroAO));
        if(CollectionUtils.isEmpty(doctorPageList.getItems())){
            return ResultBuilder.success(new PageList<>());
        }
        PageList<DoctorIntroVO> voPageList = CommonTool.buildPageList(doctorPageList, DoctorIntroVO.class);
        List<Long> doctorIds = voPageList.getItems().stream().map(d->d.getId()).collect(Collectors.toList());
        Map<Long, List<Dept>> doctorIdAndDeptsMap = deptService.getDeptListByDoctorIds(doctorIds);
        DoctorTools.buildIntroVODepts(voPageList, doctorIdAndDeptsMap);
        //挂号量
        if(DoctorListTypeEnum.INTRO.getCode().equals(doctorIntroAO.getListType())){
            List<DoctorOrderCountDTO> orderCountDTOS = orderRegService.countByDoctorIds(doctorIds);
            Map<Long, Integer> dIdAndNumMap = orderCountDTOS.stream().collect(Collectors.toMap(DoctorOrderCountDTO::getDoctorId, DoctorOrderCountDTO::getNum));
            voPageList.getItems().forEach(d->{
                d.setRegNum(dIdAndNumMap.get(d.getId()));
            });
        }
        //设置医院名称、头像全路径
        voPageList.getItems().forEach(vo->{
            vo.setHosName(appName);
            vo.setFullHeadPhotoPath(PhotoTools.getFullPath(customConf.getFileUrl(), vo.getHeadPhoto()));
        });
        return ResultBuilder.success(voPageList);
    }

    @ApiOperation("医生介绍")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.SELECT, desc = "医生介绍")
    @PostMapping("/docDesc")
    public ResultDTO<PageList<DoctorIntroVO>> docDesc(@RequestBody DoctorDescAO doctorDescAO) {
        DoctorDTO doctorDTO = DoctorTools.buildDoctorDTO(doctorDescAO);
        DoctorIntroDTO doctorIntroDTO = CommonTool.copyProperties(doctorDTO, DoctorIntroDTO.class);
        doctorIntroDTO.setDeptDescId(doctorDescAO.getDeptDescId());
        PageList<Doctor> doctorPageList = doctorService.doctorIntroList(doctorIntroDTO);
        if(CollectionUtils.isEmpty(doctorPageList.getItems())){
            return ResultBuilder.success(new PageList<>());
        }
        PageList<DoctorIntroVO> voPageList = CommonTool.buildPageList(doctorPageList, DoctorIntroVO.class);
        //dept info
        List<Long> doctorIds = voPageList.getItems().stream().map(d->d.getId()).collect(Collectors.toList());
        Map<Long, List<Dept>> doctorIdAndDeptsMap = deptService.getDeptListByDoctorIds(doctorIds);
        DoctorTools.buildIntroVODepts(voPageList, doctorIdAndDeptsMap);
        //挂号量
        List<DoctorOrderCountDTO> orderCountDTOS = orderRegService.countByDoctorIds(doctorIds);
        Map<Long, Integer> dIdAndNumMap = orderCountDTOS.stream().collect(Collectors.toMap(DoctorOrderCountDTO::getDoctorId, DoctorOrderCountDTO::getNum));
        voPageList.getItems().forEach(d->{
            d.setRegNum(dIdAndNumMap.get(d.getId()));
        });
        //设置医院名称、头像全路径
        voPageList.getItems().forEach(vo->{
            vo.setHosName(appName);
            vo.setFullHeadPhotoPath(PhotoTools.getFullPath(customConf.getFileUrl(), vo.getHeadPhoto()));
        });
        return ResultBuilder.success(voPageList);
    }

    @ApiOperation("医生基本信息")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.SELECT, desc = "医生基本信息")
    @PostMapping("/docBaseInfo")
    public ResultDTO<DoctorIntroVO> docBaseInfo(@RequestBody DoctorIntroVO doctorIntro)  throws Exception{
        CommonTool.checkObj(doctorIntro.getId(), "90000007");
        Doctor doctor = doctorService.findById(doctorIntro.getId());
        DoctorIntroVO doctorIntroVO = CommonTool.copyProperties(doctor, DoctorIntroVO.class);
        doctorIntroVO.setFullHeadPhotoPath(PhotoTools.getFullPath(customConf.getFileUrl(), doctor.getHeadPhoto()));
        doctorIntroVO.setHosName(appName);
        return ResultBuilder.success(doctorIntroVO);
    }

    @ApiOperation("医生公告-列表")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.SELECT, desc = "医生公告-列表")
    @PostMapping("/announcementList")
    public ResultDTO<PageList<DoctorAnnouncementVO>> announcementList(@RequestBody DoctorAnnouncementListAO listAO) {
        PageList<DoctorAnnouncement> pageList = announcementService.list(CommonTool.copyProperties(listAO, DoctorAnnouncementDTO.class));
        return ResultBuilder.success(CommonTool.buildPageList(pageList, DoctorAnnouncementVO.class));
    }

    @ApiOperation("医生公告")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.SELECT, desc = "医生公告")
    @PostMapping("/announcement")
    public ResultDTO<DoctorAnnouncementVO> announcement(@RequestBody DoctorAnnouncementAO announcementAO) {
        DoctorAnnouncementDTO dto = new DoctorAnnouncementDTO();
        dto.setDoctorId(announcementAO.getDoctorId());
        PageList<DoctorAnnouncement> pageList = announcementService.list(dto);
        if(pageList == null || CollectionUtils.isEmpty(pageList.getItems())){
            return ResultBuilder.success();
        }
        return ResultBuilder.success(CommonTool.copyProperties(pageList.getItems().get(0), DoctorAnnouncementVO.class));
    }

    @ApiOperation("医生评价-患者提交")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.ADD, desc = "医生评价-患者提交")
    @PostMapping("/evaluationAdd")
    public ResultDTO evaluationAdd(@RequestBody DoctorEvaAddAO evaAddAO) {
        if(evaAddAO.getDoctorId() == null || evaAddAO.getPatientId() == null || evaAddAO.getLabels() == null || evaAddAO.getOnlineOrderId() == null){
            return ResultBuilder.failure("10120001", "参数有误");
        }
        Patient patient = patientService.findById(evaAddAO.getPatientId());
        evaluationService.insert(DoctorTools.buildEvaAddAO2Model(evaAddAO, patient));
        return ResultBuilder.success();
    }

    @ApiOperation("医生评价-患者查询订单是否评价")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.SELECT, desc = "医生评价-患者查询订单是否评价")
    @PostMapping("/queryOrderIsEvalution")
    public ResultDTO queryOrderIsEvalution(@RequestBody DoctorEvaAddAO evaAddAO) {
        if(evaAddAO.getOnlineOrderId() == null){
            return ResultBuilder.failure("10120001", "参数有误");
        }
        DoctorDiagnosisEvaluation doctorDiagnosisEvaluation = evaluationService.queryByDataId(evaAddAO.getOnlineOrderId());
        Integer isEvaluetion = doctorDiagnosisEvaluation == null ? 0 : 1;
        return ResultBuilder.success(isEvaluetion);
    }

    @ApiOperation("医生评价-列表")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.SELECT, desc = "医生评价-列表")
    @PostMapping("/evaluationList")
    public ResultDTO<PageList<DoctorEvaListVO>> evaluationList(@RequestBody DoctorEvaListAO listAO) {
        DoctorDiagnosisEvaluationDTO evaluationDTO = DoctorTools.buildEvaluation(listAO);
        PageList<DoctorDiagnosisEvaluation> pageList = evaluationService.list(evaluationDTO);
        return ResultBuilder.success(DoctorTools.buildEvaListModel2VO(pageList));
    }

    @ApiOperation("医生问诊-停诊状态(0:停诊，1:开启)")
    @Log(source = LogSourceEnum.PATIENT_APP, type = LogTypeEnum.SELECT, desc = "医生问诊-停诊状态(0:停诊，1:开启)")
    @PostMapping("/onlineStatus")
    public ResultDTO<Integer> onlineStatus(@RequestBody DoctorOnlineStatusAO statusAO) {
        DoctorDiagnosisSettings settings = doctorDiagnosisSettingsService.getDoctorDiagnosisSettingsByDoctorId(statusAO.getDoctorId());
        return ResultBuilder.success(settings.getDiagnosisFlag());
    }


}
